#include <iostream>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

#include <MemoriaCompartida.h>
#include <BaseException.h>

using namespace std;

int main (int argc, char* argv[])
{
	try
	{
		string nombreMemoriaCompartida = argv[0];
		int cantCambios = 200;
		int valorFinal;
		
		pid_t pid = fork ();
		
		if ( pid == 0 )
		{
			cout << "HIJO: PID:" << getpid() << endl;
			cout << "HIJO: Voy a crear la memoria compartida " << nombreMemoriaCompartida << endl;
			
			MemoriaCompartida<int> mem;
			mem.crear(nombreMemoriaCompartida);
			cout << "HIJO: Memoria compartida creada" << endl;
			
			int i, aux;
			cout << "HIJO: Modifico la memoria compartida " << cantCambios << " veces" << endl;
			for( i =0; i < cantCambios; i++)
			{
				mem.lock();
				aux = mem.leer();
				aux++;
				mem.escribir(aux);
				mem.unlock();
			}
			
			sleep(1);
			cout << "HIJO: Valores modificados exitosamente. Libero memoria" << endl;
			mem.liberar();
			
			cout << "HIJO: Memoria liberada, finalizo" << endl;
			return 0;
		}
		else 
		{
			cout << "PADRE: PID:" << getpid() << endl;
			cout << "PADRE: Espero 1 segundo para que mi hijo cree la memoria" << endl;
			sleep(1);
			
			cout << "PADRE: Voy a unirme a la memoria compartida " << nombreMemoriaCompartida << endl;
			
			MemoriaCompartida<int> mem;
			mem.unirse(nombreMemoriaCompartida);
			cout << "PADRE: Memoria compartida unida" << endl;
			
			int i, aux;
			cout << "PADRE: Modifico la memoria compartida " << cantCambios << " veces" << endl;
			for( i =0; i < cantCambios; i++)
			{
				mem.lock();
				aux = mem.leer();
				aux--;
				mem.escribir(aux);
				mem.unlock();
			}
			
			cout << "PADRE: Valores modificados." << endl;
			
			cout << "PADRE: Espero a que mi hijo finalice" << endl;
			int estado;
			wait( (void*) &estado);
			cout << "PADRE: Mi hijo finalizo" << endl;
			
			valorFinal = mem.leerSincronizado();
			mem.liberar();
			
			if(valorFinal != 0)
				cout << "PADRE: El valor final esperado era 0 pero se obtuvo " << valorFinal << endl;
			else
				cout << "PADRE: testMemoriaCompartida OK" << endl;
		}
	}
	catch (const BaseException& e) {
		std::cerr << "testMemoriaCompartida FAIL" << std::endl;
		std::cerr << e.what() << std::endl;
	}
}